package com.mytx.search.controller;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mytx.common.constant.Constant;
import com.mytx.common.pojo.CommonResult;
import com.mytx.common.pojo.RedisLock;
import com.mytx.common.utils.DateUtils;
import com.mytx.common.utils.EntityUtils;
import com.mytx.mapper.OrdersMapper;
import com.mytx.mapper.UserMapper;
import com.mytx.pojo.OrderReceiveInfo;
import com.mytx.pojo.Orders;
import com.mytx.pojo.OrdersExample;
import com.mytx.pojo.User;
import com.mytx.search.utils.PayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@SuppressWarnings({"SpringJavaInjectionPointsAutowiringInspection", "Duplicates"})
@RestController
public class OrderController {
    private static final Logger logger = LoggerFactory.getLogger(OrderController.class);

    @Autowired
    private HttpServletRequest request;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    UserMapper userMapper;
    @Autowired
    OrdersMapper ordersMapper;

    @PostMapping("/syncOrderData")
    public CommonResult syncOrderData(@RequestBody String orderId) {

        Orders orders = ordersMapper.selectByPrimaryKey(orderId);

        return CommonResult.ok(orders);
    }

    @Transactional
    @PostMapping("/cancelOrder")
    public CommonResult cancelOrder(@RequestBody String orderId) {
        String uId = request.getHeader("uId");

        RedisLock lock = new RedisLock(redisTemplate, orderId);//以订单id 加锁
        try {
            if (!lock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "未获取到锁");
            }
            Object orderObject = redisTemplate.opsForValue().get(Constant.ORDER_RECORD + orderId);
            if (orderObject == null) {
                logger.error("cancelOrder:取消订单异常，ORDER_RECORD 缓存中没有记录，人工介入，uid:{},orderId:{}", uId, orderId);
                return CommonResult.build(Constant.ORDER_INVALID, "订单无效");
            }
            Orders order = (Orders) orderObject;
            Integer status = order.getStatus();
            if (status != Constant.ORDER_STATUS_INIT && status != Constant.ORDER_STATUS_OFFER_SUCCESS) {
                return CommonResult.build(Constant.ORDER_STATUS_ERROR, "当前订单状态不能取消");
            }
            User buyerUserInfo = null;

            //取消拍卖竞价成功的订单
            boolean isAuctionOrder = status == Constant.ORDER_STATUS_OFFER_SUCCESS;
            if (isAuctionOrder) {

                if (order.getuId().equals(uId)) { // 买家取消订单，需要从用户余额中扣除保证金对应的金额给卖家
                    order.setStatus(Constant.ORDER_STATUS_BUYER_CANCELLED);
                    BigDecimal deposit = order.getDeposit();
                    buyerUserInfo = userMapper.payV2(uId, deposit, deposit);//买家扣除保证金
                    String sellerId = order.getSellerId();
                    BigDecimal sellerMysqlBalance = userMapper.incrementBalance(sellerId, deposit);//卖家增加账户余额
                    redisTemplate.opsForHash().putAll(Constant.USER_SESSION + uId, EntityUtils.objectToMap_v1(buyerUserInfo));
                    redisTemplate.opsForHash().put(Constant.USER_SESSION + sellerId, Constant.BALANCE, deposit);
                    logger.info("cancelOrder:买家取消拍卖订单,买家余额减少 uId:{},orderId:{},amount:{},balance:{}", uId, orderId, deposit, buyerUserInfo.getBalance());
                    logger.info("cancelOrder:买家取消拍卖订单,买家保证金释放 uId:{},orderId:{},amount:{},deposit:{}", uId, orderId, deposit, buyerUserInfo.getDeposit());
                    logger.info("cancelOrder:买家取消拍卖订单,卖家余额增加 uId:{},orderId:{},amount:{},balance:{}", uId, orderId, deposit, sellerMysqlBalance);

                } else {//卖家取消订单，保证金退还给买家
                    order.setStatus(Constant.ORDER_STATUS_SELLER_CANCELLED);
                    BigDecimal mysqlDeposit = userMapper.reduceDeposit(order.getuId(), order.getDeposit());
                    redisTemplate.opsForHash().put(Constant.USER_SESSION + uId, Constant.DEPOSIT, mysqlDeposit);
                    logger.info("cancelOrder:卖家取消拍卖订单,买家保证金释放 uId:{},orderId:{},amount:{},deposit:{}", uId, orderId, order.getDeposit(), mysqlDeposit);
                }
            }
            Orders updateOrder = new Orders();
            updateOrder.setId(orderId);
            updateOrder.setStatus(order.getStatus());
            ordersMapper.updateByPrimaryKeySelective(order);
            JSONObject info = new JSONObject();
            if (order.getuId().equals(uId)) {//买家取消，推送通知给卖家
                info.put("uId", order.getSellerId());
            } else {//卖家取消，推送通知给买家
                info.put("uId", order.getuId());
            }
            info.put("order", order);
            redisTemplate.convertAndSend(Constant.NOTIFY_ORDER_INFO, info);

            //取消订单后，清除缓存
            redisTemplate.delete(Constant.ORDER_RECORD + orderId);
            //如果是拍卖订单，应该删除 支付过期set 中的该笔订单id
            if (order.getType() == Constant.ORDER_TYPE_TO_AUCTION_TOPIC) {
                Date delayPayExpiryDate = DateUtils.addHour(order.getExpiryDate(), 1);//在支付过期时间的基础上加1小时，作为自动扣除保证金的时间点
                String payExpiryKey = DateUtils.formatDate(delayPayExpiryDate, DateUtils.DATE_FORMAT_DATE_HOUR);
                Long removePayExpiry = redisTemplate.opsForSet().remove(Constant.ORDER_PAY_EXPIRY_SET + payExpiryKey, orderId);
                if (removePayExpiry == null || removePayExpiry != 1) {
                    logger.error("cancelOrder:清除支付过期set出错，需要人工介入 orderId:{},payExpiryKey:{}", orderId, payExpiryKey);
                }
            }
            return CommonResult.ok(buyerUserInfo);
        } catch (InterruptedException e) {
            e.printStackTrace();
            return CommonResult.build(Constant.UNKNOWN_ERROR, "锁里面出错");

        } finally {
            lock.unlock();
        }
    }

    //卖家取消已经支付的订单
    @Transactional
    @PostMapping("/cancelPaidOrder")
    public CommonResult cancelPaidOrder(@RequestBody String orderId) {
        String uId = request.getHeader("uId");

        RedisLock lock = new RedisLock(redisTemplate, orderId);//以订单id 加锁
        try {
            if (!lock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "未获取到锁");
            }
            Object orderObject = redisTemplate.opsForValue().get(Constant.ORDER_RECORD + orderId);
            if (orderObject == null) {
                logger.error("cancelOrder:取消订单异常，ORDER_RECORD 缓存中没有记录，人工介入，uid:{},orderId:{}", uId, orderId);
                return CommonResult.build(Constant.ORDER_INVALID, "订单无效");
            }
            Orders order = (Orders) orderObject;
            Integer status = order.getStatus();
            if (status != Constant.ORDER_STATUS_PAID) {
                return CommonResult.build(Constant.ORDER_STATUS_ERROR, "非已经支付的订单");
            }
            User buyerUserInfo = null;
            if (order.getuId().equals(uId)) {
                return CommonResult.build(Constant.ORDER_STATUS_ERROR, "买家不能取消已经付款的订单");
            }
            order.setStatus(Constant.ORDER_STATUS_SELLER_CANCEL_ON_PAID);
            BigDecimal mysqlBalance = userMapper.incrementBalance(order.getuId(), order.getAmount());
            Orders updateOrder = new Orders();
            updateOrder.setId(orderId);
            updateOrder.setStatus(order.getStatus());
            ordersMapper.updateByPrimaryKeySelective(order);
            Date receiveExpiryDate = order.getExpiryDate();
            logger.info("cancelOrder:卖家取消已经支付的订单，买家余额增加 uId:{},orderId:{},amount:{},balance:{}", uId, orderId, order.getAmount(), mysqlBalance);
            //清除自动收货记录
            Date delayReceiveExpiryDate = DateUtils.addHour(receiveExpiryDate, 1);//在自动收货过期时间的基础上加1小时，作为自动扣除保证金的时间点
            String receiveExpiryKey = DateUtils.formatDate(delayReceiveExpiryDate, DateUtils.DATE_FORMAT_DATE_HOUR);
            Long autoReceiveRemove = redisTemplate.opsForSet().remove("ORDER_AUTO_RECEIVE_SET:" + receiveExpiryKey, orderId);//从自动收货缓存记录set中清除当前已经收货的order
            if (autoReceiveRemove != 1) {//清除自动收货缓存失败，需要人工介入，检查
                logger.error("refund:清除自动收货的缓存失败，需要人工介入，orderId:{}", orderId);
            }
            JSONObject info = new JSONObject();
            info.put("uId", order.getuId());
            info.put("order", order);
            redisTemplate.convertAndSend(Constant.NOTIFY_ORDER_INFO, info);

            //取消订单后，清除缓存
            redisTemplate.delete(Constant.ORDER_RECORD + orderId);

            return CommonResult.ok(buyerUserInfo);
        } catch (InterruptedException e) {
            e.printStackTrace();
            return CommonResult.build(Constant.UNKNOWN_ERROR, "锁里面出错");

        } finally {
            lock.unlock();
        }
    }


    @Transactional
    @PostMapping("/payOrder")
    public CommonResult payOrder(@RequestBody JSONObject body) {
        String uId = request.getHeader("uId");
        Orders updateOrder = body.getObject("order", Orders.class);
        String payPassword = body.getString("payPassword");
        User user = getUser(uId);
        String orderId = updateOrder.getId();
        RedisLock lock = new RedisLock(redisTemplate, orderId);//以订单id 加锁

        try {
            if (!lock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "未获取到锁");
            }
            Object orderObject = redisTemplate.opsForValue().get(Constant.ORDER_RECORD + orderId);
            if (orderObject == null) {
                logger.error("payOrder:取消订单异常，ORDER_RECORD 缓存中没有记录，人工介入，uid:{},orderId:{}", uId, orderId);
                return CommonResult.build(Constant.ORDER_INVALID, "订单已取消或者过期");
            }
            Orders order = (Orders) orderObject;
            CommonResult commonResult = PayUtils.payPrepare(payPassword, order.getAmount(), user);
            if (commonResult != null) {
                return commonResult;
            }

            Integer status = order.getStatus();
            //只有处于初始化状态的普通订单和 出价成功的订单  能支付
            if ((order.getType() == Constant.ORDER_TYPE_NORMAL && status != Constant.ORDER_STATUS_INIT) || status != Constant.ORDER_STATUS_OFFER_SUCCESS) {
                return CommonResult.build(Constant.ORDER_STATUS_ERROR, "当前订单状态不能支付");
            }
            BigDecimal mysqlBalance;
            BigDecimal deposit = null;
            if (order.getDeposit() == null) {
                mysqlBalance = userMapper.reduceBalance(uId, order.getAmount());
            } else {//同时减少账户余额和保证金 金额
                User user1 = userMapper.payV2(uId, order.getAmount(), order.getDeposit());
                mysqlBalance = user1.getBalance();
                deposit = user1.getDeposit();
            }
            updateOrder.setUpdated(new Date());
            updateOrder.setStatus(Constant.ORDER_STATUS_PAID);//把订单状态改为已经支付
            updateOrder.setSendStatus(Constant.ORDER_SEND_STATUS_WAIT_SEND);
            Date payExpiryDate = order.getExpiryDate();
            Date receiveExpiryDate = DateUtils.getDate(6);//6天自动收货
            updateOrder.setExpiryDate(receiveExpiryDate);
            ordersMapper.updateByPrimaryKeySelective(updateOrder);
            order.setExpiryDate(receiveExpiryDate);
            //判断收货地址是否是新增的，如果是，就保存起来
            List<OrderReceiveInfo> orderReceiveInfoList = user.getOrderReceiveInfos();
            if (orderReceiveInfoList == null) {
                OrderReceiveInfo newOrderReceiveInfo = new OrderReceiveInfo(updateOrder.getContact(), updateOrder.getPhone(), updateOrder.getAddress());
                orderReceiveInfoList = new ArrayList();
                orderReceiveInfoList.add(newOrderReceiveInfo);
                updateUserOrderReceiveInfo(uId, orderReceiveInfoList);
            } else {

                boolean isNewOrderReceiveInfo = true;
                for (int i = orderReceiveInfoList.size() - 1; i >= 0; i--) {
                    OrderReceiveInfo info = orderReceiveInfoList.get(i);
                    // 联系人 地址 电话都相同，认定为旧的订单接收信息
                    if (info.getContact().equals(updateOrder.getContact()) && info.getPhone().equals(updateOrder.getPhone()) && info.getAddress().equals(updateOrder.getAddress())) {
                        isNewOrderReceiveInfo = false;
                        break;
                    }
                }

                if (isNewOrderReceiveInfo) {
                    orderReceiveInfoList.add(new OrderReceiveInfo(updateOrder.getContact(), updateOrder.getPhone(), updateOrder.getAddress()));
                    updateUserOrderReceiveInfo(uId, orderReceiveInfoList);
                }
            }

            redisTemplate.opsForHash().put(Constant.USER_SESSION, Constant.BALANCE, mysqlBalance);
            if (deposit != null) {
                redisTemplate.opsForHash().put(Constant.USER_SESSION, Constant.DEPOSIT, deposit);
            }
            order.setStatus(Constant.ORDER_STATUS_PAID);//把已经支付的状态缓存进redis
            order.setSendStatus(Constant.ORDER_SEND_STATUS_WAIT_SEND);

            //如果是拍卖订单，应该去 支付过期set 中删除该笔订单id
            if (order.getType() == Constant.ORDER_TYPE_TO_AUCTION_TOPIC) {
                Date delayPayExpiryDate = DateUtils.addHour(payExpiryDate, 1);//在支付过期时间的基础上加1小时，作为自动扣除保证金的时间点
                String payExpiryKey = DateUtils.formatDate(delayPayExpiryDate, DateUtils.DATE_FORMAT_DATE_HOUR);
                Long removePayExpiry = redisTemplate.opsForSet().remove(Constant.ORDER_PAY_EXPIRY_SET + payExpiryKey, orderId);
                if (removePayExpiry == null || removePayExpiry != 1) {
                    logger.error("payOrder:清除支付过期set出错，需要人工介入 orderId:{},payExpiryKey:{}", orderId, payExpiryKey);
                }
            }
            redisTemplate.opsForValue().set(Constant.ORDER_RECORD + orderId, order);
            JSONObject info = new JSONObject();
            info.put("uId", order.getSellerId());
            info.put("order", order);
            redisTemplate.convertAndSend(Constant.NOTIFY_ORDER_INFO, info);
            JSONObject result = new JSONObject();
            result.put(Constant.BALANCE, mysqlBalance);
            if (deposit != null) {
                logger.info("payOrder:保证金减少 uId:{}, orderId:{},amount:{}, deposit:{}", uId, orderId, order.getDeposit(), deposit);
                result.put(Constant.DEPOSIT, deposit);
            }
            logger.info("payOrder:余额减少 uId:{},orderId:{}, amount:{}, balance:{}", uId, orderId, order.getAmount(), mysqlBalance);
            return CommonResult.ok(result);
        } catch (InterruptedException e) {
            e.printStackTrace();
            return CommonResult.build(Constant.UNKNOWN_ERROR, "锁里面出错");
        } finally {
            lock.unlock();
        }

    }

    /**
     * 订单发货
     *
     * @param updateOrder 包含物流单号
     * @return
     */
    @PostMapping("/orderSend")
    public CommonResult orderSend(@RequestBody Orders updateOrder) {
        String uId = request.getHeader("uId");
        String orderId = updateOrder.getId();
        RedisLock lock = new RedisLock(redisTemplate, orderId);//以订单id 加锁
        try {
            if (!lock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "未获取到锁");
            }
            Object orderObject = redisTemplate.opsForValue().get(Constant.ORDER_RECORD + orderId);
            if (orderObject == null) {
                logger.error("orderSend:订单发货异常，ORDER_RECORD 缓存中没有记录，人工介入，uid:{},orderId:{}", uId, orderId);
                return CommonResult.build(Constant.ORDER_INVALID, "订单无效");
            }
            Orders order = (Orders) orderObject;
            Integer originalStatus = order.getStatus();
            //只有未发货状态能发货
            if (order.getSendStatus() != null && order.getSendStatus() != Constant.ORDER_SEND_STATUS_WAIT_SEND) {
                return CommonResult.build(Constant.ORDER_STATUS_ERROR, "当前订单状态不能发货");
            }
            Date orignalexpiryDate = order.getExpiryDate();
            Date receiveExpiryDate = DateUtils.getDate(6);//6天自动收货
            Date updated = new Date();
            updateOrder.setStatus(Constant.ORDER_STATUS_SENT);
            updateOrder.setSendStatus(Constant.ORDER_SEND_STATUS_SENT);
            updateOrder.setExpiryDate(receiveExpiryDate);
            updateOrder.setUpdated(updated);
            ordersMapper.updateByPrimaryKeySelective(updateOrder);
            //把发货后的相关信息更新到redis
            order.setExpiryDate(receiveExpiryDate);
            order.setExpressId(updateOrder.getExpressId());
            order.setStatus(Constant.ORDER_STATUS_SENT);
            order.setSendStatus(Constant.ORDER_SEND_STATUS_SENT);
            Integer refundStatus = order.getRefundStatus();
            //原本的订单状态是退款中的话，需要设置退款状态为中断状态
            if (originalStatus == Constant.ORDER_STATUS_REFUNDING) {
                order.setRefundStatus(Constant.ORDER_REFUND_STATUS_INTERRUPT);
            }
            order.setUpdated(updated);
            redisTemplate.opsForValue().set(Constant.ORDER_RECORD + orderId, order);
            //从发货开始，涉足6天的自动收货时间
            Date delayReceiveExpiryDate = DateUtils.addHour(receiveExpiryDate, 1);//在自动收货过期时间的基础上加1小时，作为自动收货的时间点
            String receiveExpiryKey = DateUtils.formatDate(delayReceiveExpiryDate, DateUtils.DATE_FORMAT_DATE_HOUR);
            redisTemplate.opsForSet().add(Constant.ORDER_AUTO_RECEIVE_SET + receiveExpiryKey, orderId);
            //原来是退款状态，需要去 自动同意退款的 set中清除掉该订单 id
            if (originalStatus == Constant.ORDER_STATUS_REFUNDING) {
                String refundExpiryKey = DateUtils.formatDate(orignalexpiryDate, DateUtils.DATE_FORMAT_DATE_HOUR);
                Long refundRemove = redisTemplate.opsForSet().remove(Constant.ORDER_REFUND_SET + refundExpiryKey, orderId);
                if (refundRemove != 1) {//说明清除退款缓存失败，需要人工介入，检查
                    logger.error("orderSend:清除退款缓存失败，需要人工介入，orderId:{}", orderId);
                }
            }

            JSONObject info = new JSONObject();
            info.put("uId", order.getuId());
            info.put("order", order);
            redisTemplate.convertAndSend(Constant.NOTIFY_ORDER_INFO, info);

            return CommonResult.ok();
        } catch (InterruptedException e) {
            e.printStackTrace();
            return CommonResult.build(Constant.UNKNOWN_ERROR, "锁里面出错");
        } finally {
            lock.unlock();
        }
    }


    @PostMapping("/modifyOrderSendInfo")
    public CommonResult modifyOrderSendInfo(@RequestBody Orders updateOrder) {
        String uId = request.getHeader("uId");
        String orderId = updateOrder.getId();
        RedisLock lock = new RedisLock(redisTemplate, orderId);//以订单id 加锁
        try {
            if (!lock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "未获取到锁");
            }
            Object orderObject = redisTemplate.opsForValue().get(Constant.ORDER_RECORD + orderId);
            if (orderObject == null) {
                logger.error("modifyOrderSendInfo:修改订单发货信息异常，ORDER_RECORD 缓存中没有记录，人工介入，uid:{},orderId:{}", uId, orderId);
                return CommonResult.build(Constant.ORDER_INVALID, "订单无效");
            }
            Orders order = (Orders) orderObject;
            if (order.getSendStatus() != null && order.getSendStatus() != Constant.ORDER_SEND_STATUS_SENT) {
                return CommonResult.build(Constant.ORDER_STATUS_ERROR, "当前订单状态不能修改订单发货信息");
            }
            Date updated = new Date();
            updateOrder.setUpdated(updated);
            ordersMapper.updateByPrimaryKeySelective(updateOrder);
            order.setExpressId(updateOrder.getExpressId());
            order.setUpdated(updated);
            redisTemplate.opsForValue().set(Constant.ORDER_RECORD + orderId, order);
            return CommonResult.ok();
        } catch (InterruptedException e) {
            e.printStackTrace();
            return CommonResult.build(Constant.UNKNOWN_ERROR, "锁里面出错");
        } finally {
            lock.unlock();
        }
    }


    /**
     * 收货
     *
     * @param order
     * @return
     */
    @Transactional
    @PostMapping("/receive")
    public CommonResult receive(@RequestBody Orders order) {
        String uId = request.getHeader("uId");

        String orderId = order.getId();
        RedisLock lock = new RedisLock(redisTemplate, orderId);
        try {
            if (!lock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "获取锁失败");
            }
            Date receiveExpiryDate = order.getExpiryDate();
            Date delayReceiveExpiryDate = DateUtils.addHour(receiveExpiryDate, 1);//在自动收货过期时间的基础上加1小时，作为自动扣除保证金的时间点
            String receiveExpiryKey = DateUtils.formatDate(delayReceiveExpiryDate, DateUtils.DATE_FORMAT_DATE_HOUR);
            Boolean member = redisTemplate.opsForSet().isMember(Constant.ORDER_AUTO_RECEIVE_SET + receiveExpiryKey, orderId);
            if (!member) {
                logger.error("receive:订单收货异常，ORDER_AUTO_RECEIVE_SET 缓存中没有记录，人工介入，uid:{},orderId:{}", uId, orderId);
                return CommonResult.build(Constant.ORDER_INVALID, "订单无效");
            }
            Object orderObject = redisTemplate.opsForValue().get(Constant.ORDER_RECORD + orderId);
            if (orderObject == null) {
                logger.error("receive:订单收货异常，ORDER_RECORD 缓存中没有记录，人工介入，uid:{},orderId:{}", uId, orderId);
                return CommonResult.build(Constant.ORDER_INVALID, "订单无效");
            }
            order = (Orders) orderObject;
            BigDecimal orderBalance = order.getAmount();
            //如果是订单状态是退款完成，那么卖家收到的金额等于订单金额减去退款金额
            if (order.getStatus() == Constant.ORDER_STATUS_REFUND_COMPLETED && order.getRefund() != null) {
                orderBalance = order.getAmount().subtract( order.getRefund());
            }
            String sellerId = order.getSellerId();
            order.setStatus(Constant.ORDER_STATUS_TRADE_SUCCESS);
            order.setSendStatus(Constant.ORDER_SEND_STATUS_RECEIVED);
            order.setUpdated(new Date());
            ordersMapper.updateByPrimaryKeySelective(order);
            BigDecimal mysqlBalance = userMapper.incrementBalance(sellerId, orderBalance);
            redisTemplate.opsForHash().put(Constant.USER_SESSION + sellerId, Constant.BALANCE, mysqlBalance);
            JSONObject info = new JSONObject();
            info.put("uId", sellerId);
            info.put("order", order);
            redisTemplate.convertAndSend(Constant.NOTIFY_ORDER_INFO, info);
            logger.info("receive:订单收货余额增加，uId:{},orderId:{},amount:{},balance:{}", sellerId, orderId, orderBalance, mysqlBalance);
            Long autoReceiveRemove = redisTemplate.opsForSet().remove("ORDER_AUTO_RECEIVE_SET:" + receiveExpiryKey, orderId);//从自动收货缓存记录set中清除当前已经收货的order
            if (autoReceiveRemove != 1) {//清除自动收货缓存失败，需要人工介入，检查
                logger.error("agreeRefund:清除自动收货的缓存失败，需要人工介入，orderId:{}", orderId);
            }
            redisTemplate.delete(Constant.ORDER_RECORD + orderId);//清除订单缓存
            return CommonResult.ok();
        } catch (InterruptedException e) {
            e.printStackTrace();
            logger.error("agreeRefund:收货出错" + e.getMessage());
            return CommonResult.build(Constant.UNKNOWN_ERROR, "未知错误");
        }

    }

    /**
     * 买方发起退款
     *
     * @return
     */
    @PostMapping("/refund")
    public CommonResult refund(@RequestBody Orders updateOrder) {
        String uId = request.getHeader("uId");
        String orderId = updateOrder.getId();

        RedisLock lock = new RedisLock(redisTemplate, orderId);
        try {
            if (!lock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "获取锁失败");
            }
            Object orderObject = redisTemplate.opsForValue().get(Constant.ORDER_RECORD + orderId);
            if (orderObject == null) {
                logger.warn("refund:ORDER_RECORD 缓存中没有记录，uid:{},orderId:{}", uId, orderId);
                return CommonResult.build(Constant.ORDER_INVALID, "订单无效");
            }
            Orders order = (Orders) orderObject;
            if (updateOrder.getRefund().compareTo(order.getAmount())>0) {
                return CommonResult.build(Constant.ILLEGAL_ACCESS, "非法访问");
            }
            //判断是否是第一次查询，如果不是，需要先去前一次退款产生的自动退款set中做清除
            int refundCount = 1;
            if (order.getRefundCount() != null) {
                refundCount += order.getRefundCount();
                String refundExpiryKey = DateUtils.formatDate(order.getExpiryDate(), DateUtils.DATE_FORMAT_DATE_HOUR);
                Long refundRemove = redisTemplate.opsForSet().remove(Constant.ORDER_REFUND_SET + refundExpiryKey, order.getId());
                if (refundRemove != 1) {//说明清除退款缓存失败，需要人工介入，检查
                    logger.error("refund:清除退款缓存失败，需要人工介入，orderId:{}", order.getId());
                }
            }
            Date refundExpiryDate = DateUtils.getDate(2);
            order.setRefundCount(refundCount);
            order.setExpiryDate(refundExpiryDate);
            order.setRefund(updateOrder.getRefund());
            //当客户端上传了退款原因，需要更新进缓存
            List<String> reasons = updateOrder.getReasons();
            if (reasons != null && reasons.size() != 0) {
                order.getReasons().addAll(reasons);
                updateOrder.setReasons(order.getReasons());
            }
            //订单状态设置为退款中，单独保存退款状态 ，这样当卖家拒绝退款后，还能拿到退款状态，重新同意退款，
            order.setStatus(Constant.ORDER_STATUS_REFUNDING);
            order.setRefundStatus(updateOrder.getRefundStatus());
            Date updated = new Date();
            order.setUpdated(updated);
            updateOrder.setStatus(Constant.ORDER_STATUS_REFUNDING);
            updateOrder.setRefundCount(refundCount);
            updateOrder.setExpiryDate(refundExpiryDate);
            updateOrder.setUpdated(updated);
            ordersMapper.updateByPrimaryKeySelective(updateOrder);
            //以到期日期的年月日小时部分作为key 保存进redis,以便在定时任务中做到期自动退款的处理
            String refundExpiryKey = DateUtils.formatDate(refundExpiryDate, DateUtils.DATE_FORMAT_DATE_HOUR);
            redisTemplate.opsForSet().add(Constant.ORDER_REFUND_SET + refundExpiryKey, order.getId());

            //已经发货，把订单id 从自动收货的key 中清除，避免已经申请了退款，又被自动收货了
            if (order.getSendStatus() == Constant.ORDER_SEND_STATUS_SENT) {
                Date receiveExpiryDate = order.getExpiryDate();
                Date delayReceiveExpiryDate = DateUtils.addHour(receiveExpiryDate, 1);//在自动收货过期时间的基础上加1小时，作为自动扣除保证金的时间点
                String receiveExpiryKey = DateUtils.formatDate(delayReceiveExpiryDate, DateUtils.DATE_FORMAT_DATE_HOUR);
                Long receiveRemove = redisTemplate.opsForSet().remove(Constant.ORDER_AUTO_RECEIVE_SET + receiveExpiryKey, order.getId());
                if (receiveRemove != 1) {//清除自动收货的缓存失败，需要人工介入，检查
                    logger.error("agreeRefund:清除自动收货的缓存失败，需要人工介入，orderId:{}", order.getId());
                }
            }
            redisTemplate.opsForValue().set(Constant.ORDER_RECORD + orderId, order);//更新缓存
            JSONObject info = new JSONObject();
            info.put("uId", order.getSellerId());
            info.put("order", order);
            redisTemplate.convertAndSend(Constant.NOTIFY_ORDER_INFO, info);
            return CommonResult.ok(refundExpiryDate);
        } catch (InterruptedException e) {
            e.printStackTrace();
            logger.error("cancelRefund:取消退款出错" + e.getMessage());
            return CommonResult.build(Constant.UNKNOWN_ERROR, "未知错误");
        } finally {
            lock.unlock();
        }
    }

    @PostMapping("/cancelRefund")
    public CommonResult cancelRefund(@RequestBody String orderId) {
        String uId = request.getHeader("uId");

        RedisLock lock = new RedisLock(redisTemplate, orderId);
        try {
            if (!lock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "获取锁失败");
            }
            Object orderObject = redisTemplate.opsForValue().get(Constant.ORDER_RECORD + orderId);
            if (orderObject == null) {
                logger.warn("refund:ORDER_RECORD 缓存中没有记录，uid:{},orderId:{}", uId, orderId);
                return CommonResult.build(Constant.ORDER_INVALID, "订单无效");
            }
            Orders order = (Orders) orderObject;
            Integer status = order.getStatus();
            //只有  退款状态 和 卖家拒绝退款状态 能  取消退款
            if (status != Constant.ORDER_STATUS_REFUNDING && status != Constant.ORDER_STATUS_REFUSE_REFUND) {
                return CommonResult.build(Constant.ORDER_STATUS_ERROR, "当前订单状态不能取消退款");
            }

            //取消退款后，重新设置订单状态为  付款状态
            order.setStatus(Constant.ORDER_STATUS_CANCEL_REFUND);
            order.setRefund(BigDecimal.ZERO);
            Date updated = new Date();
            Date currentDate = updated;
            order.setUpdated(currentDate);
            Orders updateOrder = new Orders();
            updateOrder.setId(orderId);
            updateOrder.setStatus(Constant.ORDER_STATUS_CANCEL_REFUND);
            updateOrder.setUpdated(currentDate);
            ordersMapper.updateByPrimaryKeySelective(updateOrder);
            redisTemplate.opsForValue().set(Constant.ORDER_RECORD + orderId, order);
            if (status != Constant.ORDER_STATUS_REFUSE_REFUND) {//当订单状态不是 拒绝退款状态，需要去 自动退款的set中删除订单id
                String refundExpiryKey = DateUtils.formatDate(order.getExpiryDate(), DateUtils.DATE_FORMAT_DATE_HOUR);
                Long refundRemove = redisTemplate.opsForSet().remove(Constant.ORDER_REFUND_SET + refundExpiryKey, orderId);
                if (refundRemove != 1) {//说明清除退款缓存失败，需要人工介入，检查
                    logger.error("cancelRefund:清除退款缓存失败，需要人工介入，orderId:{}", orderId);
                }
            }
            JSONObject info = new JSONObject();
            info.put("uId", order.getSellerId());
            info.put("order", order);
            redisTemplate.convertAndSend(Constant.NOTIFY_ORDER_INFO, info);

            return CommonResult.ok();
        } catch (InterruptedException e) {
            e.printStackTrace();
            logger.error("cancelRefund:取消退款出错" + e.getMessage());
            return CommonResult.build(Constant.UNKNOWN_ERROR, "未知错误");
        } finally {
            lock.unlock();
        }

    }

    /**
     * 卖方 同意退款
     *
     * @return
     */
    @Transactional
    @PostMapping("/agreeRefund")
    public CommonResult agreeRefund(@RequestBody String orderId) {
        String uId = request.getHeader("uId");
        RedisLock lock = new RedisLock(redisTemplate, orderId);
        try {
            if (!lock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "获取锁失败");
            }

            Object orderObject = redisTemplate.opsForValue().get(Constant.ORDER_RECORD + orderId);
            if (orderObject == null) {
                logger.warn("refund:ORDER_RECORD 缓存中没有记录，uid:{},orderId:{}", uId, orderId);
                return CommonResult.build(Constant.ORDER_INVALID, "订单无效");
            }
            Orders order = (Orders) orderObject;
            if (order.getStatus() != Constant.ORDER_STATUS_REFUNDING) {
                return CommonResult.build(Constant.ORDER_STATUS_ERROR, "订单非退款状态");
            }

            String buyerId = order.getuId();
            BigDecimal refund = order.getRefund();
            BigDecimal mysqlBalance = null;
            Integer refundStatus = order.getRefundStatus();
            if (refundStatus == Constant.ORDER_REFUND_STATUS_NOT_RECEIVED_REFUND_ALL || refundStatus == Constant.ORDER_REFUND_STATUS_RECEIVED_REFUND_PART) {//退款后交易结束
                order.setStatus(Constant.ORDER_STATUS_REFUND_COMPLETED);
                mysqlBalance = userMapper.incrementBalance(buyerId, refund);
                redisTemplate.opsForHash().put(Constant.USER_SESSION + buyerId, Constant.BALANCE, mysqlBalance);
            } else {//设置订单状态为 同意退款，需要 买家退回商品
                order.setStatus(Constant.ORDER_STATUS_AGREE_REFUND_GOODS);
                //把订单加入退货的set中，到期没有退货，自动按买家放弃退款处理，扣款给卖家，结束交易
                //ORDER_REFUND_GOODS_SET
                Date refundGoodsExpiryDate = DateUtils.getDate(9);//设置9天的退货期限，买家需要在这期间内做出处理
                order.setExpiryDate(refundGoodsExpiryDate);
                String refundGoodsExpiryKey = DateUtils.formatDate(refundGoodsExpiryDate, DateUtils.DATE_FORMAT_DATE_HOUR);
                redisTemplate.opsForSet().add(Constant.ORDER_REFUND_GOODS_SET + refundGoodsExpiryKey, orderId);
            }
            Date updated = new Date();
            order.setUpdated(updated);
            Orders updateOrder = new Orders();
            updateOrder.setId(orderId);
            updateOrder.setStatus(order.getStatus());
            updateOrder.setExpiryDate(order.getExpiryDate());
            updateOrder.setUpdated(updated);
            ordersMapper.updateByPrimaryKeySelective(updateOrder);
            redisTemplate.opsForValue().set(Constant.ORDER_RECORD + orderId, order);
            String refundExpiryKey = DateUtils.formatDate(order.getExpiryDate(), DateUtils.DATE_FORMAT_DATE_HOUR);
            Long refundRemove = redisTemplate.opsForSet().remove(Constant.ORDER_REFUND_SET + refundExpiryKey, orderId);
            if (refundRemove != 1) {//说明清除退款缓存失败，需要人工介入，检查
                logger.error("agreeRefund:清除退款缓存失败，需要人工介入，orderId:{}", orderId);
            }
            JSONObject info = new JSONObject();
            info.put("uId", buyerId);
            info.put("order", order);
            redisTemplate.convertAndSend(Constant.NOTIFY_ORDER_INFO, info);
            if (mysqlBalance != null) {//日志放最后，避免mysql进入事务回滚了，而日志却残留了下来
                logger.info("agreeRefund:卖家同意退款，买家余额增加，uId:{},orderId:{},amount:{},balance:{}", buyerId, orderId, refund, mysqlBalance);
            }
            return CommonResult.ok();
        } catch (InterruptedException e) {
            e.printStackTrace();
            logger.error("agreeRefund:同意退款出错" + e.getMessage());
            return CommonResult.build(Constant.UNKNOWN_ERROR, "未知错误");
        } finally {
            lock.unlock();
        }

    }

    /**
     * 拒绝退款
     *
     * @param updateOrder
     * @return
     */
    @PostMapping("/refuseRefund")
    public CommonResult refuseRefund(@RequestBody Orders updateOrder) {


        String uId = request.getHeader("uId");
        String orderId = updateOrder.getId();
        RedisLock lock = new RedisLock(redisTemplate, orderId);//以订单id 加锁
        try {
            if (!lock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "未获取到锁");
            }
            Object orderObject = redisTemplate.opsForValue().get(Constant.ORDER_RECORD + orderId);
            if (orderObject == null) {
                logger.error("cancelOrder:取消订单异常，ORDER_RECORD 缓存中没有记录，人工介入，uid:{},orderId:{}", uId, orderId);
                return CommonResult.build(Constant.ORDER_INVALID, "订单无效");
            }
            Orders order = (Orders) orderObject;
            Integer status = order.getStatus();
            //只有退款状态能  拒绝退款
            if (status != Constant.ORDER_STATUS_REFUNDING) {
                return CommonResult.build(Constant.ORDER_STATUS_ERROR, "当前订单状态不能拒绝退款");
            }
            Date updated = new Date();
            updateOrder.setStatus(Constant.ORDER_STATUS_REFUSE_REFUND);
            updateOrder.setUpdated(updated);
            ordersMapper.updateByPrimaryKeySelective(updateOrder);
            //把拒绝后的相关信息更新到redis
            order.setExpressId(updateOrder.getExpressId());
            order.setStatus(Constant.ORDER_STATUS_REFUSE_REFUND);
            order.setReasons(updateOrder.getReasons());
            order.setUpdated(updated);
            redisTemplate.opsForValue().set(Constant.ORDER_RECORD + orderId, order);
            //拒绝退款，把订单id 从自动退款的缓存set 中清除
            String refundExpiryKey = DateUtils.formatDate(order.getExpiryDate(), DateUtils.DATE_FORMAT_DATE_HOUR);
            Long refundRemove = redisTemplate.opsForSet().remove(Constant.ORDER_REFUND_SET + refundExpiryKey, order.getId());
            if (refundRemove != 1) {//说明清除退款缓存失败，需要人工介入，检查
                logger.error("agreeRefund:清除自动退款缓存失败，需要人工介入，orderId:{}", order.getId());
            }
            JSONObject info = new JSONObject();
            info.put("uId", order.getuId());
            info.put("order", order);
            redisTemplate.convertAndSend(Constant.NOTIFY_ORDER_INFO, info);
            return CommonResult.ok();
        } catch (InterruptedException e) {
            e.printStackTrace();
            return CommonResult.build(Constant.UNKNOWN_ERROR, "锁里面出错");
        } finally {
            lock.unlock();
        }
    }

    @PostMapping("/queryMyBuyOrder")
    public CommonResult queryMyBuyOrder(@RequestBody Map<String, Object> info) {
        String uId = request.getHeader("uId");
        int page = 1;
        int size = 10;
        if (info.containsKey("page")) {
            page = (int) info.get("page");
        }
        if (info.containsKey("size")) {
            size = (int) info.get("size");
        }

        PageHelper.startPage(page, size);
        List<Orders> orders = ordersMapper.selectMyBuyOrders(uId);
        PageInfo<Orders> offerPageInfo = new PageInfo<>(orders);
        return CommonResult.ok(offerPageInfo);
    }

    @PostMapping("/queryMySellOrder")
    public CommonResult queryMySellOrder(@RequestBody Map<String, Object> info) {
        String uId = request.getHeader("uId");
        int page = 1;
        int size = 10;
        if (info.containsKey("page")) {
            page = (int) info.get("page");
        }
        if (info.containsKey("size")) {
            size = (int) info.get("size");
        }
        PageHelper.startPage(page, size);
        List<Orders> orders = ordersMapper.selectMySellOrders(uId);
        PageInfo<Orders> offerPageInfo = new PageInfo<>(orders);
        return CommonResult.ok(offerPageInfo);
    }

    @PostMapping("/deleteOrdersForBuyer")
    public CommonResult deleteOrdersForBuyer(@RequestBody List<String> orderId) {

        OrdersExample example = new OrdersExample();
        OrdersExample.Criteria criteria = example.createCriteria();
        criteria.andIdIn(orderId);
        Orders updateOrder = new Orders();
        updateOrder.setBuyerDeleteFlag(Constant.ORDER_STATUS_DELETE);
        updateOrder.setUpdated(new Date());
        ordersMapper.updateByExampleSelective(updateOrder, example);
        return CommonResult.ok();
    }

    @PostMapping("/deleteOrdersForSeller")
    public CommonResult deleteOrdersForSeller(@RequestBody List<String> orderId) {

        OrdersExample example = new OrdersExample();
        OrdersExample.Criteria criteria = example.createCriteria();
        criteria.andIdIn(orderId);
        Orders updateOrder = new Orders();
        updateOrder.setSellerDeleteFlag(Constant.ORDER_STATUS_DELETE);
        updateOrder.setUpdated(new Date());
        ordersMapper.updateByExampleSelective(updateOrder, example);
        return CommonResult.ok();
    }

    private User getUser(String uId) {
        Map<Object, Object> entries = redisTemplate.opsForHash().entries(Constant.USER_SESSION + uId);
        if(entries.isEmpty()){
            return  userMapper.selectByPrimaryKey(uId);
        }
        return JSONObject.parseObject(JSONObject.toJSONString(entries), User.class);
    }

    /**
     * 更新用户收货信息
     *
     * @param uId
     * @param orderReceiveInfoList
     */
    private void updateUserOrderReceiveInfo(String uId, List<OrderReceiveInfo> orderReceiveInfoList) {
        User updateUser = new User();
        updateUser.setuId(uId);
        updateUser.setOrderReceiveInfos(orderReceiveInfoList);
        userMapper.updateByPrimaryKeySelective(updateUser);
        redisTemplate.opsForHash().put(Constant.USER_SESSION, "OrderReceiveInfoList", orderReceiveInfoList);
    }

}
